package cn.green.utils;

import cn.green.core.adapt.models.field.*;
import cn.green.core.adapt.models.table.OrmTable;
import cn.green.core.annos.column.QColumn;
import cn.green.core.annos.feature.QDeleted;
import cn.green.core.annos.feature.QParentKy;
import cn.green.core.annos.feature.QPrimary;
import cn.green.core.annos.reles.OneToMany;
import cn.green.core.annos.reles.OneToOne;
import cn.green.core.annos.reles.RevOneToMany;
import cn.green.core.annos.reles.RevOneToOne;
import cn.green.core.annos.table.QTable;
import cn.green.core.components.setter.DeleteKey;
import cn.green.core.components.setter.PrimaryKey;
import cn.green.core.model.QFieldModel;
import cn.green.core.scanner.store.OrmTableStore;
import cn.green.mapper.model.impls.table.EntityTableMapper;
import cn.green.mapper.model.FieldColumnMapper;
import cn.green.mapper.model.impls.field.DynamicFieldColumnMapper;
import cn.green.mapper.model.impls.field.NormalFieldColumnMapper;
import cn.green.mapper.model.impls.field.OneToManyFieldColumnMapper;
import cn.green.mapper.model.impls.field.OneToOneFieldColumnMapper;
import cn.green.mapper.store.EntityTableMapperStore;
import cn.green.mng.curd.QOrmFieldCurd;
import cn.green.mvc.entity.OrmTableEntity;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wang.yishu
 * @version 1.0
 * @className ColumnUtils
 * @description 字段工具
 * todo 该组件之后需要重构
 * @date 2025/5/22 11:00
 */
public class ColumnUtils {

    public static void setOrmFieldCurd(QOrmFieldCurd ormFieldCurd) {
        ColumnUtils.ormFieldCurd = ormFieldCurd;
    }

    private static QOrmFieldCurd ormFieldCurd;

    public static OrmTable buildOrmTable(Class<?> clazz, boolean needBuildRelevant) {
        OrmTable ormTable = createOrmTable(clazz);
        if (ormTable == null) {
            return null;
        }
        EntityTableMapper entityTableMapper = new EntityTableMapper();
        List<FieldColumnMapper> mappers = new ArrayList<>();
        buildPrimaryKey(mappers, ormTable, clazz);
        buildDeleteKey(mappers, ormTable, clazz);
        buildParentKey(mappers, ormTable, clazz);
        //建造固定字段：实体类内部定义的属性字段
        buildOrmColumn(mappers, ormTable, clazz);
        //建造动态字段：后期人为通过表管理加入的字段
        buildNotOrmColumn(mappers, ormTable, clazz);
        //对于关联字段，则再最后进行
        if (needBuildRelevant) {
            buildRelevantColumn(mappers, ormTable, clazz);
        }
        entityTableMapper.setFieldColumnMappers(mappers);
        entityTableMapper.setTableModel(ormTable);
        entityTableMapper.setEntityClass((Class<OrmTableEntity>) clazz);
        EntityTableMapperStore.add(clazz, entityTableMapper);
        return ormTable;
    }

    public static void buildPrimaryKey(List<FieldColumnMapper> mappers, OrmTable ormTable, Class<?> tableType) {
        Field[] fields = tableType.getDeclaredFields();
        if (fields.length > 0) {
            Arrays.stream(fields).filter(item -> item.getAnnotation(QPrimary.class) != null && item.getAnnotation(QColumn.class) != null).findFirst().ifPresent(
                item -> {
                    QPrimary annotation = item.getAnnotation(QPrimary.class);
                    Class<? extends PrimaryKey> primaryType = annotation.primary();
                    if (primaryType != null) {
                        try {
                            ormTable.setPrimaryKey(primaryType.newInstance());
                        } catch (InstantiationException | IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    OrmField primary = new OrmField(tableType, ormTable, item);
                    primary.setCanUpdate(false);
                    primary.setCanDelete(false);
                    primary.setCanBeUseForConditionStr("0");
                    NormalFieldColumnMapper normalFieldColumnMapper = new NormalFieldColumnMapper();
                    normalFieldColumnMapper.setColumn(primary);
                    normalFieldColumnMapper.setField(item);
                    mappers.add(normalFieldColumnMapper);
                    ormTable.setPrimary(primary);
                }
            );
        }
    }

    public static  void buildDeleteKey(List<FieldColumnMapper> mappers , OrmTable ormTable, Class<?> tableType) {
        Field[] fields = tableType.getDeclaredFields();
        if (fields.length > 0) {
            Arrays.stream(fields).filter(item -> item.getAnnotation(QDeleted.class) != null && item.getAnnotation(QColumn.class) != null).findFirst().ifPresent(
                    item -> {
                        QDeleted annotation = item.getAnnotation(QDeleted.class);
                        Class<? extends DeleteKey> deletedType = annotation.deleted();
                        if (deletedType != null) {
                            try {
                                ormTable.setDeleteKey(deletedType.newInstance());
                            } catch (InstantiationException | IllegalAccessException e) {
                                throw new RuntimeException(e);
                            }
                        }
                        OrmField deleted = new OrmField(tableType, ormTable, item);
                        deleted.setCanUpdate(false);
                        deleted.setCanDelete(false);
                        NormalFieldColumnMapper normalFieldColumnMapper = new NormalFieldColumnMapper();
                        normalFieldColumnMapper.setColumn(deleted);
                        normalFieldColumnMapper.setField(item);
                        mappers.add(normalFieldColumnMapper);
                        ormTable.setDeleted(deleted);
                    }
            );
        }
    }

    public static void buildParentKey(List<FieldColumnMapper> mappers , OrmTable ormTable, Class<?> tableType) {
        Field[] fields = tableType.getDeclaredFields();
        if (fields.length > 0) {
            Arrays.stream(fields).filter(item -> item.getAnnotation(QParentKy.class) != null && item.getAnnotation(QColumn.class) != null).findFirst().ifPresent(
                    item -> {
                        OrmField parentKey = new OrmField(tableType, ormTable, item);
                        parentKey.setCanUpdate(false);
                        parentKey.setCanDelete(false);

                        NormalFieldColumnMapper normalFieldColumnMapper = new NormalFieldColumnMapper();
                        normalFieldColumnMapper.setColumn(parentKey);
                        normalFieldColumnMapper.setField(item);
                        mappers.add(normalFieldColumnMapper);
                        ormTable.setParent(parentKey);
                    }
            );
        }
    }

    public static void buildOrmColumn(List<FieldColumnMapper> mappers , OrmTable ormTable, Class<?> tableType) {
        Field[] fields = tableType.getDeclaredFields();
        if (fields.length > 0) {
            List<QFieldModel> fieldModels = new ArrayList<>();
            Arrays.stream(fields).filter(item ->
                            item.getAnnotation(QPrimary.class) == null
                            && item.getAnnotation(QParentKy.class) == null
                            && item.getAnnotation(QDeleted.class) == null
                            && item.getAnnotation(QColumn.class) != null
                            )
                    .forEach(item -> {
                        if (item.getAnnotation(QColumn.class) != null) {
                            OrmField ormField = new OrmField(tableType, ormTable, item);
                            ormField.setCanUpdate(false);
                            ormField.setCanDelete(false);
                            NormalFieldColumnMapper normalFieldColumnMapper = new NormalFieldColumnMapper();
                            normalFieldColumnMapper.setColumn(ormField);
                            normalFieldColumnMapper.setField(item);
                            normalFieldColumnMapper.setQColumn(item.getAnnotation(QColumn.class));
                            mappers.add(normalFieldColumnMapper);
                            fieldModels.add(ormField);
                        }
                    });
            ormTable.setFields(fieldModels);
        }
    }

    public static void buildNotOrmColumn(List<FieldColumnMapper> mappers , OrmTable ormTable, Class<?> tableType) {
        List<QFieldModel> ormFields = ColumnUtils.ormFieldCurd.findNotOrmFields(ormTable.getSourceName(), ormTable.getSchemeName(), ormTable.getTableName());
        if (ormFields != null && !ormFields.isEmpty()) {
            List<QFieldModel> fields = ormTable.allFields();
            List<QFieldModel> normalFields = ormTable.getFields();
            fields = fields == null ? new ArrayList<>() : fields;
            normalFields = normalFields == null ? new ArrayList<>() : normalFields;
            for (QFieldModel ormField : ormFields) {
                if (fields.stream().anyMatch(item -> item.getFieldName().equals(ormField.getFieldName()))) {
                    throw new RuntimeException("field " + ormField.getFieldName() + " is exist");
                }
                ormField.setCanDelete(true);
                ormField.setCanUpdate(true);
                DynamicFieldColumnMapper dynamicFieldColumnMapper = new DynamicFieldColumnMapper();
                dynamicFieldColumnMapper.setColumn(ormField);
                mappers.add(dynamicFieldColumnMapper);
                normalFields.add(ormField);
            }
            ormTable.setFields(normalFields);
        }
    }

    public static void buildRelevantColumn(List<FieldColumnMapper> mappers , OrmTable ormTable, Class<?> tableType) {
        Field[] fields = tableType.getDeclaredFields();
        if (fields.length > 0) {
            List<QFieldModel> fieldModels = new ArrayList<>();
            Arrays.stream(fields).filter(item ->
                    item.getAnnotation(OneToOne.class) != null
                            ||  item.getAnnotation(OneToMany.class) != null
            ).forEach(item -> {
                OneToOne oneToOne = null;
                OneToMany oneToMany = null;
                RevOneToOne revOneToOne = null;
                RevOneToMany revOneToMany = null;
                if ((oneToOne = item.getAnnotation(OneToOne.class)) != null) {
                    OrmOneToOne ormOneToOne = new OrmOneToOne(tableType, ormTable, item);
                    ormOneToOne.setCanUpdate(false);
                    ormOneToOne.setCanDelete(false);
                    fieldModels.add(ormOneToOne);
                    OneToOneFieldColumnMapper oneToOneFieldColumnMapper = new OneToOneFieldColumnMapper();
                    oneToOneFieldColumnMapper.setColumn(ormOneToOne);
                    oneToOneFieldColumnMapper.setField(item);
                    oneToOneFieldColumnMapper.setMapperClass(oneToOne.target());
                    mappers.add(oneToOneFieldColumnMapper);
                } else if ((oneToMany = item.getAnnotation(OneToMany.class)) != null) {
                    OrmOneToMany ormOneToMany = new OrmOneToMany(tableType, ormTable, item);
                    ormOneToMany.setCanUpdate(false);
                    ormOneToMany.setCanDelete(false);
                    fieldModels.add(ormOneToMany);
                    OneToManyFieldColumnMapper oneToManyFieldColumnMapper = new OneToManyFieldColumnMapper();
                    oneToManyFieldColumnMapper.setColumn(ormOneToMany);
                    oneToManyFieldColumnMapper.setField(item);
                    oneToManyFieldColumnMapper.setMapperClass(oneToMany.target());
                    mappers.add(oneToManyFieldColumnMapper);
                } else if ((revOneToOne = item.getAnnotation(RevOneToOne.class)) != null) {
                    OrmRevOneToOne ormRevOneToOne = new OrmRevOneToOne(tableType, ormTable, item);
                    ormRevOneToOne.setCanUpdate(false);
                    ormRevOneToOne.setCanDelete(false);
                    fieldModels.add(ormRevOneToOne);
                    OneToManyFieldColumnMapper oneToManyFieldColumnMapper = new OneToManyFieldColumnMapper();
                    oneToManyFieldColumnMapper.setColumn(ormRevOneToOne);
                    oneToManyFieldColumnMapper.setField(item);
                    oneToManyFieldColumnMapper.setMapperClass(revOneToOne.target());
                    mappers.add(oneToManyFieldColumnMapper);
                } else if ((revOneToMany = item.getAnnotation(RevOneToMany.class)) != null) {
                    OrmRevOneToMany ormRevOneToMany = new OrmRevOneToMany(tableType, ormTable, item);
                    ormRevOneToMany.setCanUpdate(false);
                    ormRevOneToMany.setCanDelete(false);
                    fieldModels.add(ormRevOneToMany);
                    OneToManyFieldColumnMapper oneToManyFieldColumnMapper = new OneToManyFieldColumnMapper();
                    oneToManyFieldColumnMapper.setColumn(ormRevOneToMany);
                    oneToManyFieldColumnMapper.setField(item);
                    oneToManyFieldColumnMapper.setMapperClass(revOneToMany.target());
                    mappers.add(oneToManyFieldColumnMapper);
                }
            });
            List<QFieldModel> fieldsList = ormTable.getFields();
            if (fieldsList == null) {
                fieldsList = new ArrayList<>();
            }
            fieldsList.addAll(fieldModels);
            ormTable.setFields(fieldsList);
        }
    }

    public static OrmTable createOrmTable(Class<?> clazz) {
        QTable annotation = clazz.getAnnotation(QTable.class);
        if (annotation != null) {
            OrmTable ormTable = new OrmTable();
            ormTable.setSourceName(annotation.source());
            ormTable.setSchemeName(annotation.scheme());
            ormTable.setTableName(annotation.name());
            ormTable.setOldTableName(annotation.oldName());
            ormTable.setTableAliasName(annotation.alias());
            ormTable.setTableType(annotation.type());
            ormTable.setClazz(clazz);
            String version = annotation.version();
            ormTable.setTableCode(ormTable.getSourceName() + "_" + ormTable.getSchemeName() + "_" + ormTable.getTableName() + "_version_" + version);
            ormTable.setVersion(version);
            return ormTable;
        }
        return null;
    }

    public static QFieldModel getField(String sourceName, String schemeName, String tableName, String column) {
        OrmTable ormTable = OrmTableStore.get(sourceName, schemeName, tableName);
        if (ormTable != null) {
            //没有找到对应的表
            List<QFieldModel> qFieldModels = ormTable.allFields();
            if (qFieldModels != null && !qFieldModels.isEmpty()) {
                List<QFieldModel> collect = qFieldModels.stream().filter(item -> item.getFieldName().equals(column)).collect(Collectors.toList());
                if (!collect.isEmpty()) {
                    return collect.get(0);
                }
            }
        }
        //去动态表组件找
        return ormFieldCurd.getField(sourceName, schemeName, tableName, column);
    }

    public static QFieldModel getField(String sourceName, String schemeName, String tableName, Field field) {
        OrmTable ormTable = OrmTableStore.get(sourceName, schemeName, tableName);
        if (ormTable == null) {
            //没有找到对应的表
            return null;
        }
        List<QFieldModel> qFieldModels = ormTable.allFields();
        if (qFieldModels != null && !qFieldModels.isEmpty()) {
            List<QFieldModel> collect = qFieldModels.stream().filter(item -> item.getFieldName().equals(field.getName())).collect(Collectors.toList());
            if (!collect.isEmpty()) {
                return collect.get(0);
            }
        }
        return null;
    }

    public static QFieldModel getField(Class<?> clazz, String column) {
        QTable qTable = clazz.getDeclaredAnnotation(QTable.class);
        OrmTable ormTable = OrmTableStore.get(qTable.source(), qTable.scheme(), qTable.name());
        if (ormTable == null) {
            //没有找到对应的表
            ormTable = buildOrmTable(clazz, false);
            if (ormTable == null) {
                return null;
            }
            OrmTableStore.add(ormTable);
        }
        List<QFieldModel> qFieldModels = ormTable.allFields();
        if (qFieldModels != null && !qFieldModels.isEmpty()) {
            List<QFieldModel> collect = qFieldModels.stream().filter(item -> item.getFieldName().equals(column)).collect(Collectors.toList());
            if (!collect.isEmpty()) {
                return collect.get(0);
            }
        }
        return null;
    }

    public static QFieldModel getField(Class<?> clazz, Field field) {
        QTable qTable = clazz.getDeclaredAnnotation(QTable.class);
        QColumn qColumn = field.getDeclaredAnnotation(QColumn.class);
        if (qColumn == null) {
            return null;
        }
        OrmTable ormTable = OrmTableStore.get(qTable.source(), qTable.scheme(), qTable.name());
        if (ormTable == null) {
            //没有找到对应的表
            ormTable = buildOrmTable(clazz, false);
            if (ormTable == null) {
                return null;
            }
            OrmTableStore.add(ormTable);
        }
        List<QFieldModel> qFieldModels = ormTable.allFields();
        if (qFieldModels != null && !qFieldModels.isEmpty()) {
            List<QFieldModel> collect = qFieldModels.stream().filter(item -> item.getFieldName().equals(qColumn.name())).collect(Collectors.toList());
            if (!collect.isEmpty()) {
                return collect.get(0);
            }
        }
        return null;
    }
}
